package com.org.util;

import com.org.dto.CalculateFkPlanForm;
import com.org.dto.CwPaymentPlanDto;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 收房合同录入：根据合同租约信息生成付款计划信息
 *
 * @author ASUS
 */
public class PayMentPlanGenerator {

    public static void main(String[] args) throws ParseException {
        CalculateFkPlanForm form = new CalculateFkPlanForm();
        // 合同开始日
        form.setStartDate(new SimpleDateFormat(DateUtils.DATE_PATTERN).parse("2018-04-21"));
        // 合同结束日
        form.setEndDate(new SimpleDateFormat(DateUtils.DATE_PATTERN).parse("2018-06-15"));
        // 月租金
        form.setMonthRent(new BigDecimal(1000));
        // 押金
        form.setDepositMoney(new BigDecimal(500));
        // 押几
        form.setDepositType(4);
        // 付几
        form.setPaymentType(1);
        // 生成付款计划
        generatePayMentPlan(form);
    }

    /**
     * 根据租约信息生成押金、出房付款计划
     *
     * @param form 租约信息
     * @return 付款计划信息
     * @throws ParseException
     */
    public static List<CwPaymentPlanDto> generatePayMentPlan(CalculateFkPlanForm form) {
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.DATE_PATTERN);
        System.out.println("合同租期:" + sdf.format(form.getStartDate()) + " ~~ " + sdf.format(form.getEndDate()));
        // 付款周期 付几
        int cycle = form.getPaymentType();
        // 最小周期（一个月）
        int minCycle = 1;
        // 各账期计划
        List<CwPaymentPlanDto> planList = new ArrayList<CwPaymentPlanDto>();
        // 总押金 = 押金 * 押几
        BigDecimal totalDeposit = form.getDepositMoney().multiply(new BigDecimal(form.getDepositType()));
        // 月租金
        BigDecimal monthRent = form.getMonthRent();
        // 足账期的金额 = 月租金 * 付几
        BigDecimal oneCycleRent = monthRent.multiply(new BigDecimal(cycle));
        // 当前账期租金(实际)
        BigDecimal currentCycleMoney = BigDecimal.ZERO;
        // 总钱数
        BigDecimal totalMoney = BigDecimal.ZERO;
        // 一天的租金 = 月租/30
        BigDecimal oneDayMoney = BigDecimal.valueOf(MyJinRongUtils.div(monthRent.doubleValue(), 30L, 2));
        // 合同开始日
        Date contractStartDate = form.getStartDate();
        // 合同截止日
        Date contractEndDate = form.getEndDate();
        // 账期开始日
        Date planStartDate = null;
        // 账期数
        int planNum = 1;
        List<CwPaymentPlanDto> payMentltems = form.getPayMentltems();
        // 首期房租之后的账期是否要重新生成
        boolean generatePlanAfterPreCycle = false;
        if (null != form.getPreCycleChange() && 1 == form.getPreCycleChange()) {
            generatePlanAfterPreCycle = true;
            planNum = 2;
            // 账期开始日 = 首期结束日 + 1
            planStartDate = DateUtils.getDateAfterDays(payMentltems.get(0).getPaymentDaysEnd(), 1);
        } else {
            // 账期开始日 = 合同起始日
            planStartDate = contractStartDate;
        }
        // 账期结束日 当前账期的结束日期是【下一账期起始日 - 1】
        Date planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, cycle), -1);// 第一个账期预计结束日

        if (contractEndDate.before(planEndDate)) {// 合同租约不足一个付款周期的账期时的押金和房租付款计划的生成
            Date currentCycleStartDate = planStartDate;
            // 当前账期租金 = 足月数 * 月租金 + 不足月天数 *月租金/30
            planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, minCycle), -1);
            if (contractEndDate.before(planEndDate)) {// 不足一个付款周期的账期时 AND 不足一个月时
                // 当前账期结束日 = 合同结束日
                planEndDate = contractEndDate;
                // 当前账期租金 = 不足月天数 *月租金/30
                double diffDay = DateUtils.getDiffDay(contractStartDate, contractEndDate);
                double mul = MyJinRongUtils.mul(oneDayMoney.doubleValue(), diffDay);
                currentCycleMoney = BigDecimal.valueOf(mul);
            } else {// 不足一个付款周期的账期时 AND 超过一个月时
                // 累加 第一个足月金额
                currentCycleMoney.add(monthRent);
                // 合同结束日期在当前账期结束日期之后
                while (contractEndDate.after(planEndDate)) {
                    // 下一个足月数起始日 AND 预计结束日
                    planStartDate = DateUtils.getDateAfterMonths(planStartDate, minCycle);
                    planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, minCycle), -1);// 预计结束日
                    // 合同结束日在该账期之后，继续写一个
                    if (contractEndDate.before(planEndDate)) {
                        planEndDate = contractEndDate;// 实际结束日
                        // 累加 不足月天数 *月租金/30
                        currentCycleMoney = currentCycleMoney.add(oneDayMoney
                                .multiply(new BigDecimal(DateUtils.getDiffDay(planStartDate, contractEndDate))));
                    } else {
                        // 累加 足月金额
                        currentCycleMoney = currentCycleMoney.add(monthRent);
                    }
                }
            }
            if (generatePlanAfterPreCycle == false) {
                // 押金不为0时，才生成押金的付款计划
                if (isNotZero(totalDeposit)) {
                    // 添加押金 计划DTO
                    totalMoney = totalMoney.add(totalDeposit);
                    addPlan(planList, planNum, BusinessCostTypesEnum.YAJIN.getIndex(), totalDeposit, planStartDate,
                            planStartDate, planEndDate);
                }
                // 添加首期金额 计划DTO
                if (isNotZero(currentCycleMoney)) {
                    totalMoney = totalMoney.add(currentCycleMoney);
                    addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
                            currentCycleStartDate, currentCycleStartDate, contractEndDate);
                }
            } else {
                // 添加第二个账期金额 计划DTO
                if (isNotZero(currentCycleMoney)) {
                    totalMoney = totalMoney.add(currentCycleMoney);
                    addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
                            getPayableDate(currentCycleStartDate), currentCycleStartDate, contractEndDate);
                }
            }
        } else {// 合同租约超过一个付款周期的账期时的押金和房租付款计划的生成
            // 累加 第一个足账期的金额
            currentCycleMoney = currentCycleMoney.add(oneCycleRent);
            if (generatePlanAfterPreCycle == false) {
                // 押金不为0时，才生成押金的付款计划
                if (isNotZero(totalDeposit)) {
                    // 添加押金 计划DTO
                    totalMoney = totalMoney.add(totalDeposit);
                    addPlan(planList, planNum, BusinessCostTypesEnum.YAJIN.getIndex(), totalDeposit, planStartDate,
                            planStartDate, planEndDate);
                }
                // 添加首期金额 计划DTO
                totalMoney = totalMoney.add(currentCycleMoney);
                addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney, planStartDate,
                        planStartDate, planEndDate);
            } else {
                // 添加第二个账期金额 计划DTO
                totalMoney = totalMoney.add(currentCycleMoney);
                addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
                        getPayableDate(planStartDate), planStartDate, planEndDate);
            }
            while (contractEndDate.after(planEndDate)) {
                planNum++;
                // 下一个账期的起始日为【前一账期的开始日加(付款周期)个月】
                planStartDate = DateUtils.getDateAfterMonths(planStartDate, cycle);
                planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, cycle), -1);
                // 【下一个付款周期的账期起始日到合同结束日】不足一个付款周期的账期时的房租付款计划的生成
                if (contractEndDate.before(planEndDate)) {
                    Date currentCycleStartDate = planStartDate;
                    // 调用不足一账期的计算处理
                    currentCycleMoney = BigDecimal.ZERO;
                    // 当前账期租金 = 足月数 * 月租金 + 不足月天数 *月租金/30
                    planEndDate = DateUtils.getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, minCycle), -1);
                    if (contractEndDate.before(planEndDate)) {// 不足一个付款周期的账期时 AND 不足一个月时
                        // 当前账期租金 = 不足月天数 *月租金/30
                        currentCycleMoney = oneDayMoney
                                .multiply(new BigDecimal(DateUtils.getDiffDay(planStartDate, contractEndDate)));
                    } else {// 不足一个付款周期的账期时 AND 超过一个月时
                        // 累加 第一个足月金额
                        currentCycleMoney.add(monthRent);
                        // 合同结束日期在当前账期结束日期之后
                        while (contractEndDate.after(planEndDate)) {
                            // 下一个足月数起始日 AND 预计结束日
                            planStartDate = DateUtils.getDateAfterMonths(planStartDate, minCycle);
                            planEndDate = DateUtils
                                    .getDateAfterDays(DateUtils.getDateAfterMonths(planStartDate, minCycle), -1);// 预计结束日
                            // 合同结束日在该账期之后，继续写一个
                            if (contractEndDate.before(planEndDate)) {
                                // 累加 不足月天数 *月租金/30
                                currentCycleMoney = currentCycleMoney.add(oneDayMoney.multiply(
                                        new BigDecimal(DateUtils.getDiffDay(planStartDate, contractEndDate))));
                            } else {
                                // 累加 足月金额
                                currentCycleMoney = currentCycleMoney.add(monthRent);
                            }
                        }
                    }
                    // 添加不足一个账期的付款计划信息
                    if (isNotZero(currentCycleMoney)) {
                        // 生成该账期的付款计划
                        totalMoney = totalMoney.add(currentCycleMoney);// 累加最后一个不足一个账期的金额
                        addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
                                getPayableDate(currentCycleStartDate), currentCycleStartDate, contractEndDate);
                    }
                } else {
                    currentCycleMoney = oneCycleRent;
                    // 生成该账期的付款计划
                    totalMoney = totalMoney.add(currentCycleMoney);
                    addPlan(planList, planNum, BusinessCostTypesEnum.ZUJIN.getIndex(), currentCycleMoney,
                            getPayableDate(planStartDate), planStartDate, planEndDate);
                }
            }
        }

        List<CwPaymentPlanDto> finalPlanList = new ArrayList<CwPaymentPlanDto>();
        if (generatePlanAfterPreCycle == true) {
            // 首期之后的账期总金额
            BigDecimal totalAmountAfterFirstCycle = totalMoney;
            // 无押金时，firstItemInfo为首期房租；有押金时，firstItemInfo为押金
            CwPaymentPlanDto firstItemInfo = payMentltems.get(0);
            finalPlanList.add(firstItemInfo);
            // 有押金时
            if (isNotZero(totalDeposit)) {
                // 添加首期房租
                CwPaymentPlanDto firstCycleRentInfo = null;
                if (payMentltems.size() > 1) {
                    firstCycleRentInfo = payMentltems.get(1);
                    // 合同周期同押金一致
                    firstCycleRentInfo.setPaymentDaysBegin(firstItemInfo.getPaymentDaysBegin());
                    firstCycleRentInfo.setPaymentDaysEnd(firstItemInfo.getPaymentDaysEnd());
                    // 首期房租 = 租期总金额 - 押金 - 首期之后的账期总金额
                    firstCycleRentInfo.setPaymentAmount(form.getTotalAmount().subtract(firstItemInfo.getPaymentAmount())
                            .subtract(totalAmountAfterFirstCycle));
                    // 添加首期房租
                    finalPlanList.add(firstCycleRentInfo);
                }
            } else {
                // 首期房租 = 租期总金额 - 押金 - 首期之后的账期总金额
                firstItemInfo.setPaymentAmount(form.getTotalAmount().subtract(totalAmountAfterFirstCycle));
            }
            // 添加首期之后的付款计划
            for (CwPaymentPlanDto cwPayMentPlanDto : planList) {
                finalPlanList.add(cwPayMentPlanDto);
            }
        } else {
            finalPlanList = planList;
        }

        for (CwPaymentPlanDto cwReceiptPlanDto : finalPlanList) {
            System.out.println(
                    "第" + cwReceiptPlanDto.getPayNumber() + "期：" + "   应付金额：" + cwReceiptPlanDto.getPaymentAmount()
                            + "   付款期间：" + sdf.format(cwReceiptPlanDto.getPaymentDaysBegin()) + "至"
                            + sdf.format(cwReceiptPlanDto.getPaymentDaysEnd()));
        }

        return finalPlanList;
    }

    /**
     * 计算应付日期
     *
     * @param planStartDate 账期开始日
     * @param
     * @param ~28之间的日期
     * @return
     */
    private static Date getPayableDate(Date planStartDate) {
        Date payableDate = null;
        payableDate = planStartDate;
        return payableDate;
    }

    /**
     * 编辑添加各个账期信息
     *
     * @param planList
     * @param payNumber        账期
     * @param itemType         款项（参照CostTypesEnum.java的定义）
     * @param paymentAmount    账期金额
     * @param payableDate      应付日期
     * @param paymentDaysBegin 账期开始日期
     * @param paymentDaysEnd   账期结束日期
     */
    private static void addPlan(List<CwPaymentPlanDto> planList, int payNumber, int itemType, BigDecimal paymentAmount,
                                Date payableDate, Date paymentDaysBegin, Date paymentDaysEnd) {
        CwPaymentPlanDto payMentPlan = new CwPaymentPlanDto();
        // 账期
        payMentPlan.setPayNumber(payNumber);
        // 款项
        payMentPlan.setItemType(itemType);
        // 应付金额
        payMentPlan.setPaymentAmount(paymentAmount);
        // 账期开始日
        payMentPlan.setPaymentDaysBegin(paymentDaysBegin);
        // 账期结束日
        payMentPlan.setPaymentDaysEnd(paymentDaysEnd);
        // 税费
        payMentPlan.setTax(BigDecimal.ZERO);
        // 应付日期
        payMentPlan.setPayableDate(payableDate);
        planList.add(payMentPlan);
    }

    private static boolean isNotZero(BigDecimal amount) {
        if (BigDecimal.ZERO.compareTo(amount) != 0) {
            return true;
        } else {
            return false;
        }
    }
}
